import json
from typing import Any, List, Union, Dict

from Core.BaseAgent import BaseAgent
from LlmModel.DoubaoModel.DoubaoModel import DoubaoModel
from utils.PromotionChecker import PromotionChecker
from utils.logger import get_logger

logger = get_logger("FormAnalyzerServiceService")


class FormAnalyzerServiceService(BaseAgent):
    """表单分析器"""

    def __init__(self):
        self.doubao_client = DoubaoModel()
        self.promotion_checker = PromotionChecker()  # 创建外包检查器实例

    def _is_form_like(self, text: str) -> bool:
        """
        判断文本是否为表单形式（检查前5个字段）
        :param text: 待检查的文本
        :return: 是否为表单形式
        """
        # 用户习惯直接复制粘贴，下面用户再给内容转成dict之前要把"请填写表单\n：" 这部分replace掉
        text = text.replace("请填写表单\n：", "")

        form_indicators = [
            "达人昵称:", "达人主页链接:", "品牌/产品名称:", "产品品类:",
            "推广周期:", "投放形式:", "报备图文价格:", "报备视频价格:",
            "折扣要求:", "创作方向:", "排竞要求:", "寄样方式:"
        ]

        count = sum(1 for indicator in form_indicators if indicator in text)
        return count >= 5  # 如果有5个以上的表单字段，认为是表单形式

    def process(self, input_data: Any) -> Any:
        pass

    def _check_form_completeness(self, text: str) -> List[str]:
        """
        检查表单完整性并返回空的必填字段列表（每个元素为指定的差异信息名称）

        :param text: 用户输入的表单文本
        :return: 空的必填字段列表，元素格式如"达人昵称:"、"达人主页链接:"等
        """
        try:
            # 定义所有必填的差异信息名称（按用户指定顺序）
            required_fields = [
                "达人昵称",
                "达人主页链接",
                "品牌/产品名称",
                "产品品类",
                "推广周期",
                "投放形式",
                "报备图文价格",
                "报备视频价格",
                "折扣要求",
                "创作方向",
                "排竞要求",
                "寄样方式"
            ]

            # 预处理文本：统一将中文冒号转为英文冒号，便于分割
            processed_text = text.replace("：", ":")
            lines = processed_text.split('\n')

            # 提取用户输入中已存在的字段及其值（键为带冒号的字段名，值为字段值）
            user_fields = {}
            for line in lines:
                line = line.strip()
                if not line or ':' not in line:
                    continue
                # 分割字段名（带冒号）和值
                field_name_with_colon, field_value = line.split(':', 1)
                field_name_with_colon = field_name_with_colon.strip().split(".", 1)[1]
                field_value = field_value.strip()
                user_fields[field_name_with_colon] = field_value

            print("-------------------------33------------------------\n")
            print(user_fields)
            print("-------------------------33------------------------\n")

            # 检查必填字段中哪些是空的（值为空或字段不存在）
            empty_fields = []
            for field in required_fields:
                # 字段不存在于用户输入中，视为空
                if field not in user_fields:
                    empty_fields.append(field)
                # 字段存在但值为空，视为空
                elif not user_fields[field]:
                    empty_fields.append(field)

            return empty_fields

        except Exception as e:
            logger.error(f"检查表单完整性失败: {str(e)}")
            # 异常时返回所有必填字段（视为全部缺失）
            return [
                "达人昵称",
                "达人主页链接",
                "品牌/产品名称",
                "产品品类",
                "推广周期",
                "投放形式",
                "报备图文价格",
                "报备视频价格",
                "折扣要求",
                "创作方向",
                "排竞要求",
                "寄样方式"
            ]

    async def _compare_forms(self, base_info: str, user_form: str) -> str:
        """
        比较两个表单的折扣要求差异------------------------------>这里比较的差异，只比较两个表单的折扣要求差异，应该是有15种差异
        """

        """
        先用大模型做差异判断，判断有没有差异，差异的内容是什么 （这个方法）
        然后再做差异的归因（流程种后面的方法）
        """

        try:
            # 提取基础表单折扣值
            base_discount = self._extract_discount(base_info)
            if base_discount is None:
                logger.error(f"无法从基础表单中提取折扣值: {base_info}")
                return "无法提取基础表单折扣值"

            # 提取用户表单折扣值
            user_discount = self._extract_discount(user_form)
            if user_discount is None:
                logger.error(f"无法从用户表单中提取折扣值: {user_form}")
                return "无法提取用户表单折扣值"

            # 比较折扣值
            if base_discount <= user_discount:
                return ""  # 符合要求，返回空字符串
            else:
                return f"折扣要求超出基础表单值。基础表单值为：{base_discount}%，用户表单值为：{user_discount}%"

        except Exception as e:
            logger.error(f"表单比较失败: {str(e)}")
            return f"表单比较失败: {str(e)}"

    async def get_forms_differ_unionDict(self, base_info: str, user_form: str,
                                         conversations: List[Dict[str, str]] = None):
        """
        比较两个表单的差异，返回包含两类差异的复合字典
        返回结构说明：
        - negotiable：dict[int, str]，原7个可议价原因（1-7键，值为空=无差异）
        - non_negotiable：dict[int, str]，新增8个不可议价原因（1-8键，值为空=无差异）
        - has_non_negotiable：bool，是否存在不可议价差异（True=有，需优先处理）
        """
        try:
            # 1. 定义两类原因的字段映射（原7个+新增8个）
            key_reasons_mapping = """
                            【可议价原因（共7个，可讨价还价）】
                            1. 返点不满足 → 严格对应"折扣要求"字段
                            2. 排竞时长不满足 → 严格对应"排竞要求"字段  
                            3. 需求不匹配 → 严格对应"投放形式、寄样方式"字段
                            4. 档期不满足 → 严格对应"推广周期"字段
                            5. 创作风格不符合 → 严格对应"创作方向"字段
                            6. 数据不保证 → 严格对应"可保阅读数据、可保互动数据"字段
                            7. 调性不匹配 → 严格对应账号调性相关字段
                            """

            non_negotiable_mapping = """
                            【不可议价原因（共8个，不可讨价还价，必须满足基础要求）】
                            1. 账号资质不符 → 账号资质不合规（如缺少必要资质认证）
                            2. 样品检测缺失 → 样品检测不合规（如缺少检测报告）
                            3. 合规声明未签 → 合规责任不合规（如未签署合规协议）
                            4. 平台权限不足 → 平台权限不合规（如缺少发布权限）
                            5. 售后保障缺失 → 售后责任不合规（如缺少售后承诺）
                            6. 发票类型不符 → 发票类型不合规（如发票类型不符合要求）
                            7. 数据备案缺失 → 数据备案不合规（如缺少数据备案号）
                            8. 合作地域超限 → 合作地域不合规（如地域限制不符合要求）
                            """

            # 准备对话上下文（用于不可议价原因判断）
            conversation_context = ""
            if conversations:
                # 只取最近几轮对话避免过长
                recent_conversations = conversations[-6:]  # 取最近3轮（6条消息）
                conversation_context = "对话记录：\n"
                for i, conv in enumerate(recent_conversations):
                    role = "用户" if conv.get("role") == "user" else "助手"
                    conversation_context += f"{role}: {conv.get('content', '')}\n"

            # 2. 构建比较提示词（修改：去掉原因4和5的检查）
            compare_prompt = f"""
    请严格比较以下两个表单的差异，分别识别"可议价原因"和"不可议价原因"：

    {key_reasons_mapping}
    {non_negotiable_mapping}

    基础表单（base_info）：
    {base_info}

    用户表单（user_form）：
    {user_form}

    {conversation_context}

    # 核心判定规则（严格遵循）：

    ## 可议价原因判定（严格字段映射）：
    - 仅当对应字段存在明确差异时才判定为可议价原因
    - 返点不满足：严格比较"折扣要求"字段，用户折扣＜基础折扣→判定为原因1
    - 排竞不满足：严格比较"排竞要求"字段，用户排竞＜基础排竞→判定为原因2
    - 需求不匹配：严格比较"投放形式、寄样方式"字段，内容不一致→判定为原因3
    - 档期不满足：严格比较"推广周期"字段，用户周期不在基础周期内→判定为原因4（此项将由专门模块检查）
    - 创作风格不符：严格比较"创作方向"字段，内容不一致→判定为原因5（此项将由专门模块检查）
    - 数据不保证：严格比较"可保阅读数据、可保互动数据"字段，用户数据＜基础数据→判定为原因6
    - 调性不匹配：严格比较账号调性相关字段，内容不一致→判定为原因7
    - 无差异的字段对应原因必须返回空字符串
    - 注意：原因4和原因5将由专门模块检查，请将这两个原因的值设为空字符串

    ## 不可议价原因判定（从对话和表单内容识别）：
    - 重点从对话和表单中识别不可议价的原因，如资质、合规、权限等问题
    - 账号资质不符：表单或对话中提及账号资质、认证等问题（如缺少美妆资质、食品资质等）
    - 样品检测缺失：表单或对话中提及检测报告、样品检测等问题（如缺少CMA检测报告）
    - 合规声明未签：表单或对话中提及合规协议、责任声明等问题（如未签署品牌合规协议）
    - 平台权限不足：表单或对话中提及平台权限、发布权限等问题（如未开通品牌合作人权限）
    - 售后保障缺失：表单或对话中提及售后服务、责任承诺等问题（如缺少售后问题协助处理承诺）
    - 发票类型不符：表单或对话中提及发票类型、开票问题（如要求普通发票但基础要求专用发票）
    - 数据备案缺失：表单或对话中提及数据备案、备案编号等问题（如缺少平台数据备案号）
    - 合作地域超限：表单或对话中提及地域限制、覆盖范围等问题（如仅选部分城市但基础要求全国）
    - 只要表单或对话中明确提及上述不可议价问题，就判定对应原因

    ## 通用规则：
    - 语义匹配：包含关系视为一致（如"种草"与"单品种草"一致）
    - 格式差异忽略（如"35%"与"35"一致）
    - 必须严格遵循映射关系，不相关的差异不返回
    - 优先处理不可议价原因，因为这类差异必须满足

    # 输出要求（强制复合JSON，无多余内容）：
    - 根节点为字典，包含3个键："negotiable"、"non_negotiable"、"has_non_negotiable"；
    - "negotiable"：字典，键为"1"-"7"（对应7个可议价原因），值为差异描述或空字符串；
    - "non_negotiable"：字典，键为"1"-"8"（对应8个不可议价原因），值为差异描述或空字符串；
    - "has_non_negotiable"：布尔值，True=存在不可议价差异，False=无此类差异；
    - 无差异时对应键值为空字符串，必须包含全部键，不可缺失。
    - 特别注意：原因4和原因5的值必须设为空字符串，这两个原因将由专门模块检查

    示例输出（正确情况）：
    {{
        "negotiable":{{"1":"返点不满足：折扣要求不一致，基础值：35%，用户值：30%","2":"","3":"","4":"","5":"","6":"","7":""}},
        "non_negotiable":{{"1":"","2":"样品检测缺失：表单中缺少CMA检测报告","3":"","4":"","5":"","6":"","7":"","8":""}},
        "has_non_negotiable":true
    }}

    示例输出（无不可议价差异）：
    {{
        "negotiable":{{"1":"返点不满足：折扣要求不一致，基础值：35%，用户值：30%","2":"","3":"","4":"","5":"","6":"","7":""}},
        "non_negotiable":{{"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}},
        "has_non_negotiable":false
    }}
                """

            # 3. 调用大模型获取复合差异结果（不包含原因4和5）
            comparison = await self.doubao_client.generate_text(compare_prompt)
            comparison = comparison.strip()

            # 4. 解析复合JSON（分离两类差异+状态）
            try:
                clean_comparison = comparison.replace("'", "\"").strip()
                result_dict = json.loads(clean_comparison)

                # 初始化默认结构（防止大模型返回缺失键）
                default_negotiable = {str(i): "" for i in range(1, 8)}
                default_non_negotiable = {str(i): "" for i in range(1, 9)}

                # 提取两类差异（用默认值兜底，避免键缺失）
                negotiable = result_dict.get("negotiable", default_negotiable)
                non_negotiable = result_dict.get("non_negotiable", default_non_negotiable)

                # 确保键是字符串类型
                negotiable = {str(k): v for k, v in negotiable.items()}
                non_negotiable = {str(k): v for k, v in non_negotiable.items()}

                # 计算不可议价状态（只要non_negotiable有一个非空值，就是True）
                has_non_negotiable = any(bool(str(val).strip()) for val in non_negotiable.values())

                # 格式校验：确保两类差异是字典且键完整
                if not isinstance(negotiable, dict) or len(negotiable) != 7:
                    negotiable = default_negotiable
                if not isinstance(non_negotiable, dict) or len(non_negotiable) != 8:
                    non_negotiable = default_non_negotiable

            except json.JSONDecodeError:
                logger.error(f"无法解析复合差异JSON（格式错误）: {comparison[:50]}...")
                negotiable = {str(i): "" for i in range(1, 8)}
                non_negotiable = {str(i): "" for i in range(1, 9)}
                has_non_negotiable = False
            except Exception as e:
                logger.error(f"解析复合差异时发生异常: {str(e)}")
                negotiable = {str(i): "" for i in range(1, 8)}
                non_negotiable = {str(i): "" for i in range(1, 9)}
                has_non_negotiable = False

            # 5. 使用外包检查器检查原因4和5
            promotion_result = await self.promotion_checker.check_promotion_period(base_info, user_form)
            creation_result = await self.promotion_checker.check_creation_direction(base_info, user_form)

            # 将外包检查结果更新到negotiable中
            if promotion_result:
                negotiable["4"] = promotion_result
            if creation_result:
                negotiable["5"] = creation_result

            # 6. 构建最终返回的复合字典
            final_result = {
                "negotiable": negotiable,  # 原7个可议价差异
                "non_negotiable": non_negotiable,  # 新增8个不可议价差异
                "has_non_negotiable": has_non_negotiable  # 快速判断状态
            }

            print("----------------------------------")
            print("最终差异结果（分离两类差异）：")
            print(f"可议价差异：{final_result['negotiable']}")
            print(f"不可议价差异：{final_result['non_negotiable']}")
            print(f"是否存在不可议价差异：{final_result['has_non_negotiable']}")
            print("----------------------------------")

            # return final_result
            return negotiable, non_negotiable, has_non_negotiable

        except Exception as e:
            logger.error(f"表单比较失败: {str(e)}")
            # 异常时返回结构完整的默认值
            return {
                "negotiable": {str(i): "" for i in range(1, 8)},
                "non_negotiable": {str(i): "" for i in range(1, 9)},
                "has_non_negotiable": False
            }

# if __name__ == '__main__':
#     formAnalyzerServiceService = FormAnalyzerServiceService()
#     res=formAnalyzerServiceService._check_form_completeness("宝子，我填好啦～\n1.达人昵称:美妆博主小雨\n2.达人主页链接:https://www.xiaohongshu.com/user/profile/5fb755d5000000000101e4c8\n3.品牌/产品名称:\n4.产品品类:美妆护肤\n5.推广周期:11月13日发布（12号有事排不开）\n6.投放形式:只能拍15秒短视频（长了粉丝没耐心），不做全肤质试色（我只有干皮粉丝）\n7.报备图文价格:15000元\n8.报备视频价格:28000元\n9.是否可以保价到次月:是\n10.折扣要求:30%（我这边最多只能给30%）\n11.创作方向:口红开箱（只拍包装和试色，不聊持久度）\n12.排竞要求:前14后15（前14天要接其他口红推广，没法空）\n13.寄样方式:品牌寄拍（包邮）\n14.达人鞋服尺码:无需\n15.免费展示套数及加价:最多2个色号，超1个加400元（多了试色太费时间）\n16.可保阅读数据:视频只能保8000播放（1.2万太高了）\n17.可保互动数据:点赞+评论≥300（转发没法保证）\n18.是否可以免费授权品牌信息流 6 个月？:最多授权3个月（6个月太长）\n19.是否可以免费授权品牌二剪及全平台传播（包括电商）6 个月？:可以授权，但抖音电商不行（我在抖音没开店）\n20.是否可以免费分发其他平台？:只同步小红书（抖音微博没运营）\n21.是否有特殊合作注意事项？:广告占比≤18%（太高粉丝会取关），脚本不能改（拍前确认好，改了要重拍）\n22.是否免费授权电商平台植入 6 个月？:不授权（怕影响粉丝信任）\n23.是否授权搜索引导6 个月？:可以授权\n24.是否授权带相关话题6 个月？:可以授权\n25.是否授权组件需求6 个月？:不授权（组件影响观看体验）\n26.是否授权引流需求6 个月？:可以授权\n27.达人账号资质:暂时没有《美妆类推广资质证书》（正在办理）\n28.样品检测报告:没准备CMA检测报告（品牌没说要啊）\n29.合规责任声明:还没签署合规声明（要先看内容）\n30.平台发布权限:没开通品牌合作人权限（粉丝还没到10万）\n31.售后责任承诺:不承诺协助售后（我这边没客服）\n32.发票开具类型:只能开增值税普通发票（专票要加税点）\n33.数据备案编号:没有平台备案编号（不知道要这个）\n34.可推广地域:只覆盖华东地区（其他地区没流量）")
#     print(res)
